import fs from 'fs';

/**
 * 模块配置
 */
export interface ModuleConfig {
    /**
     * 模块名称
     */
    name?: string;

    /**
     * 保留此模块
     */
    keep?: boolean;

    /**
     * 是否为基础模块
     */
    baseModule?: boolean;

    /**
     * 默认是否保留此模块
     */
    keepDefault?: boolean;

    /**
     * 模块描述
     */
    description?: string;

    /**
     * 库文件
     */
    libs?: string[];

    /**
     * 声明文件
     */
    types?: string[];

    /**
     * 模块依赖
     */
    dependences?: string[];

    /**
     * 模块源文件
     */
    sources?: string[];

    /**
     * 模块导出
     */
    exports?: string[];
}

/**
 * 框架配置
 */
export interface FrameworkConfig {
    /**
     * 框架名称
     */
    framework: string;

    /**
     * 模块配置
     */
    modules: {
        [key: string]: ModuleConfig;
    };
}

/**
 * 框架配置器
 */
export class FrameworkConfigurator {
    /**
     * 配置对象
     */
    private _config: FrameworkConfig = null;

    /**
     * 构建模块树
     * @param configFile 模块配置文件
     */
    constructor(config: string | FrameworkConfig) {
        if (typeof config === 'string') {
            this._config = JSON.parse(fs.readFileSync(config, { encoding: 'utf-8' }));
        } else {
            this._config = JSON.parse(JSON.stringify(config));
        }
        this.keepBaseModules();
    }

    /**
     * 获得框架名称
     */
    getFrameworkName() {
        return this._config.framework;
    }

    /**
     * 获得配置模块
     */
    getConfigModules() {
        let modules: ModuleConfig[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (!module.baseModule) {
                modules.push(module);
            }
        }
        return modules;
    }

    /**
     * 保留基础模块
     */
    keepBaseModules() {
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            module.name = module.name || mname;
            if (module.baseModule) {
                this.keepModule(mname);
            }
        }
    }

    /**
     * 保留模块数组
     * @param mnames
     */
    keepModules(mnames: string[]) {
        if (mnames) {
            for (let mname of mnames) {
                this.keepModule(mname);
            }
        }
    }

    /**
     * 保留模块
     * @param mname
     */
    keepModule(mname: string) {
        let module = this._config.modules[mname];
        if (module) {
            if (!module.keep) {
                module.keep = true;
                this.keepModules(module.dependences);
            }
        }
    }

    /**
     * 保留默认模块
     */
    keepDefaultModules() {
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keepDefault) {
                this.keepModule(mname);
            }
        }
    }

    /**
     * 保留所有模块
     */
    keepAllModules() {
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            module.keep = true;
        }
    }

    /**
     * 收集模块
     */
    collectModules() {
        let modules: ModuleConfig[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keep) {
                modules.push(module);
            }
        }
        return modules;
    }

    /**
     * 收集源文件
     */
    collectSources() {
        let sources: string[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keep && module.sources) {
                sources.push(...module.sources);
            }
        }
        return [...new Set(sources)];
    }

    /**
     * 收集库文件
     */
    collectLibs() {
        let libs: string[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keep && module.libs) {
                libs.push(...module.libs);
            }
        }
        return [...new Set(libs)];
    }

    /**
     * 收集声明文件
     */
    collectTypes() {
        let types: string[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keep && module.types) {
                types.push(...module.types);
            }
        }
        return [...new Set(types)];
    }

    /**
     * 收集导出
     */
    collectExports() {
        let exports: string[] = [];
        for (let mname in this._config.modules) {
            let module = this._config.modules[mname];
            if (module.keep && module.exports) {
                exports.push(...module.exports);
            }
        }
        return [...new Set(exports)];
    }
}
